from flask import current_app, render_template,session,jsonify,request,g
from . import index_blue
from info.models import User,News,Category,Comment
from info import constants,db
from info.utils.response_code import RET
from info.utils.commons import login_required
# from werkzeug.routing import BaseConverter
#使用蓝图注册路由　并绑定视图函数
'''装饰其一定要放在路由的后面'''
@index_blue.route("/")
@login_required
def index():

    user=g.user

    # user_id = session.get("user_id")
    # user=None
    # if user_id:
    #     try:
    #         # user=User.query.get(user_id)
    #         user= User.query.filter_by(id=user_id).first()
    #     except Exception as e:
    #         current_app.logger.error(e)
    try:
        news_list=News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询新闻数据库失败")

    if not news_list:
        return jsonify(errno=RET.DBERR,errmsg="数据库中没有数据")
    news_dict_list = []
    for news in news_list:
        news_dict_list.append(news.to_dict())
    try:
        categories = Category.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询新闻分类失败")
    if not categories:
        return jsonify(errno=RET.DBERR,errmsg='没有新闻分类数据')
    category_list=[]
    for category in categories:
        category_list.append(category)

    data = {
        "user_info": user.to_dict() if user else None,
        "news_dict_list":news_dict_list,
        "category_list":category_list,
    }
    return render_template('news/index.html', data=data)

@index_blue.route("/news_list")
def get_news_list():
    """
    显示新闻数据列表
    １　获得参数cid page per_page
    ２　校验参数
    ３　根据参数从数据库中读取数据，为分页后的列表
    ４　获得总页数，当前页数，当前页的新闻列表
    ５当前页新闻列表的具体信息　
    :return:
    """
    cid = request.args.get("cid", "1")
    page = request.args.get("page", "1")
    per_page =request.args.get("per_page","10")
    try:
        cid, page,per_page = int(cid), int(page), int(per_page)
    except Exception as e:
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    filters = []
    if cid > 1:
        filters.append(News.category_id==cid)
    try:
        paginate = News.query.filter(*filters).order_by(News.create_time.desc()).paginate(page,per_page,False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询数据库数据错误")

    total_page = paginate.pages
    current_page = paginate.page
    news_list = paginate.items
    news_dict_list = []
    for news in news_list:
        '''注意news.to_dict()是一个方法，不要忘记括号'''
        news_dict_list.append(news.to_dict())
    data = {
        "news_dict_list": news_dict_list,
        "total_page": total_page,
        "current_page": current_page,
    }
    return jsonify(errno=RET.OK, errmsg="完成数据发送", data=data)



@index_blue.route("/<int:news_id>")
@login_required
def get_news_detail(news_id):
    """
    新闻详情页面
    １　根据news_id获得正常新闻详情
    ２　个人信息展示与首页同理
    ３　点击排行与首页同理


    :param news_id:
    :return:
    """
    '''g使用前必须从flask中导入，装饰器也要导入'''
    user = g.user
    '''
       与前端练习分为:
       1 方式: 1 局部的ajax;
                   1 前端通过ajax({})发送post数据,并接收后台return jsonify()的json格式数据,在回调函数中将数据加载到
                      对应的标签上,这些都是在js的某个事件中被执行.后端通过request.json.get()获得前端ajax的数据,然后处理
                   2 当请求为get时,参数将通过request.args.get("")的形式获得
               2 模板处理;后台将数据通过render_template("模板",数据传送)将数据传送到模板中,所有数据要通过
                   模板语言及方法加载到指定的标签上,重点为模板语言的使用/


       视图函数处理流程
       1 参数
       2 校验
       3 数据库分析数据:1 判断链接数据库 2 判断连接结果
       4 数据属性及分析处理
       5 整合/返回 目标数据
       6 返回执行结果
       '''
    #　加载数据到点击排行模板
    try:
        news_list=News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询新闻数据库失败")

    if not news_list:
        return jsonify(errno=RET.DBERR,errmsg="数据库中没有数据")
    news_dict_list = []
    for new in news_list:
        news_dict_list.append(new.to_dict())
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="读取新闻详情失败")
    if not news:
        return jsonify(errno=RET.DATAERR,errmsg="没有该新闻数据")
    news.clicks += 1
    action = False
    if news.user_id and user:
        author = User.query.get(news.user_id)
        # print(author)
        if author in user.followed.all():
            action = True
    try:
        db.session.add(news)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='保存新闻数据失败')
    is_collected = False
    if user and news in user.collection_news:
        is_collected =True
        #新闻评论内容展示
    try:
        comments=Comment.query.filter_by(news_id=news_id).order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="读取新闻评论失败")
    comments_list=[]
    for comment in comments:
        comments_list.append(comment.to_dict())

    data = {
        "user_info":user.to_dict() if user else None,
        "news_detail":news.to_dict(),
        "news_dict_list": news_dict_list,
        "is_collected":is_collected,
        "comments":comments_list,
        "action":action,
    }
    return render_template("news/detail.html",data=data)


@index_blue.route("/favicon.ico")
def favicon():
    # 项目title标签中的logo图标
    # 浏览器默认会访问项目根目录下的favicon.ico文件
    # 静态路径flask会默认创建，拼接favicon文件所在的路径即可
    # http://127.0.0.1:5000/static/news/favicon.ico
    # send_static_file函数的作用是把static文件夹下的文件发给浏览器
    # 第一次实现的时候如果浏览器加载不了favicon文件：
    # 1、需要清除浏览器缓存，2、浏览器彻底退出，重新启动。
    return current_app.send_static_file('news/favicon.ico')

@index_blue.route("/news_collect", methods=["POST"])
@login_required
def news_collect():
    """
    收藏／取消收藏功能
    １　获得目前新闻的ｉｄ
    ２　获得目前收藏状态ａｃｔｉｏｎ
    ３　校验参数的完整性，转化新闻的ｉｄ数据类型
    ４　确认新闻的存在，ａｃｔｉｏｎ的指
    ５　确认用户的具体操作
    ６　返回
    :return:
    """
    # 使用g对象，从登录验证码装饰器中获取用户信息
    user = g.user
    # 如果用户未登录
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg='用户未登陆')
    news_id = request.json.get("news_id")
    action = request.json.get("action")
    if not all([news_id,action]):
        return jsonify(RET.PARAMERR,errmsg="参数不完整")
    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="新闻ｉｄ格式不对")
    if action not in ["collect", "cancel_collect"]:
        return jsonify(errno=RET.PARAMERR,errmsg="action参数错误")
    try:
        news=News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询数据库数据失败")
    if not news:
        return jsonify(errno=RET.DBERR,errmsg="无新闻数据")

    if action =="collect":
        '''
        user.collection_news 结果为一个列表,元素为该用户收藏的每个新闻对象
        '''
        if news not in user.collection_news:
            user.collection_news.append(news)
    else:
        user.collection_news.remove(news)
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg="保存数据失败")
    return jsonify(errno=RET.OK,errmsg="ok")


@index_blue.route("/news_comment", methods=["POST"])
@login_required
def news_comment():
    '''
    新闻评论
    １　确认用户登陆，获得参数news_id 评论内容content（获得参数，校验参数，校验参数的关联属性）
    ２　检验参数是否完整
    ２　校验ｉｄ格式，及新闻是否存在
    ３　将评论内容保存数据库
    ４　提交数据库
    ５　返回评论成功
    :return:
    '''
    user=g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR,errmsg="用户未登录")
    news_id=request.json.get("news_id")
    content=request.json.get("comment")
    parent_id=request.json.get("parent_id")
    # print("==========")
    # print(news_id,content)
    if not all([news_id,content]):
        return jsonify(errno=RET.PARAMERR,errmsg="参数错误")
    try:
        news_id= int(news_id)
        if parent_id:
            parent_id=int(parent_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR,errmsg="参数格式错误")
    try:
        news=News.query.filter_by(id=news_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="读取新闻数据错误")
    if not news:
        return jsonify(errno=RET.DBERR,errmsg="没有该新闻内容")
    comment=Comment()
    comment.user_id=user.id
    comment.news_id=news_id
    comment.content=content
    if parent_id:
        comment.parent_id=parent_id
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="保存数据失败")
    return jsonify(errno=RET.OK,errmsg="评论成功",data=comment.to_dict())


@index_blue.route("/user_focus", methods=["POST"])
@login_required
def user_focus():
    """
    关注／取消关注功能
    １　获得目前新闻作者的ｉｄ
    ２　获得目前关注状态ａｃｔｉｏｎ
    ３　校验参数的完整性，转化user的ｉｄ数据类型
    ４　确认user的存在，ａｃｔｉｏｎ的值
    ５　确认用户的具体操作
    ６　返回
    :return:
    """
    # 使用g对象，从登录验证码装饰器中获取用户信息
    user = g.user
    # 如果用户未登录
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg='用户未登陆')
    user_author_id = request.json.get("user_id")
    action = request.json.get("action")
    print(user_author_id,action)
    if not all([user_author_id,action]):
        return jsonify(errno=RET.PARAMERR,errmsg="11参数不完整")
    try:
        user_author_id = int(user_author_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="user的ｉｄ格式不对")
    if action not in ["focus", "cancel_focus"]:
        return jsonify(errno=RET.PARAMERR,errmsg="action参数错误")

    try:
        user_author=User.query.get(user_author_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询作者的数据失败")
    if not user_author:
        return jsonify(errno=RET.DBERR,errmsg="无该作者")
    # print(user_author,"=====",user_author_id)
    # print("**********",user.followed.all())
    if action =="focus":
        '''
        user.collection_news 结果为一个列表,元素为该用户收藏的每个新闻对象
        '''
        if user_author not in user.followed.all():
            user.followed.append(user_author)
    else:
        user.followed.remove(user_author)
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg="保存数据失败")
    return jsonify(errno=RET.OK,errmsg="ok")